// generated 2005/6/24 0:15:12 CST by xihels@163.com
//
#if defined __GNUC__ && __GNUC__ < 3
#error This program will crash if compiled with g++ 2.x
// see the dynamic_cast bug in the gtkmm FAQ
#endif //
#include "config.h"
#include <gtkmmconfig.h>
#if GTKMM_MAJOR_VERSION==2 && GTKMM_MINOR_VERSION>2
#define GMM_GTKMM_22_24(a,b) b
#else //gtkmm 2.2
#define GMM_GTKMM_22_24(a,b) a
#endif //

#include <gdk/gdkkeysyms.h>
#include <gtkmm/accelgroup.h>
#include <gtkmm/scrolledwindow.h>
#include <gtkmm/buttonbox.h>
#include <gtkmm/box.h>
#include <gtkmm/main.h>
#include <gtk/gtkmenu.h>

#include "config.h"

#include "MainWindow.h"
#include "LoginWindow.h"
#include "FindBuddyWindow.h"
#include "PreferWindow.h"
#include "MsgWindow.h"
#include "CycloneDialog.h"
#include "CycloneMenu.h"
#include "dialogAbout.h"
#include "BuddyList.h"
#include "FriendList.h"
#include "QQSession.h"
//#include "StatusIcon.h"
#include "pixmaps.h"
#include "sounds.h"

#include <stdexcept>
using namespace std;

#define SYSTEM_MENU 0
#define USER_MENU   1

MainWindow::MainWindow() :
    systemMenu(*this),
    userMenu(*this),
    findBuddyWindow(NULL)
{
    Gtk::Window *mainWindow = this;
    gmm_data = new GlademmData(get_accel_group());

    buddyList = Gtk::manage(new class BuddyList(*this));

    Gtk::ScrolledWindow *scrolledwindowFriend = 
	Gtk::manage(new class Gtk::ScrolledWindow());

    Gtk::Image* image = getImage("cyclone-system.png");
    buttonSystem = Gtk::manage( new class Gtk::Button());
    buttonSystem->add(*image);

    image = getImage("search.png");
    Gtk::Button* buttonFind = Gtk::manage(new class Gtk::Button());
    buttonFind->add(*image);
    
    pixUser[0] = getPix("menu_online.png");
    pixUser[1] = getPix("menu_away.png");
    pixUser[2] = getPix("menu_hidden.png");

    imageUser = Gtk::manage(new class Gtk::Image(pixUser[0]));
    buttonUser = Gtk::manage( new class Gtk::Button());
    buttonUser->add(*imageUser);


    Gtk::HBox* hboxMain = Gtk::manage(new class Gtk::HBox(false, 0));

    hboxMain->pack_start(*buttonSystem, Gtk::PACK_SHRINK, 0);
    hboxMain->pack_start(*buttonFind,   Gtk::PACK_SHRINK, 0);
    hboxMain->pack_start(*buttonUser);

    
    Gtk::VBox *vboxMain = Gtk::manage(new class Gtk::VBox(false, 0));

    //buddyList->set_flags(Gtk::CAN_FOCUS);
    buddyList->set_headers_visible(false);
    buddyList->set_rules_hint(true);
    buddyList->set_reorderable(true);
    buddyList->set_enable_search(true);

    buttonSystem->unset_flags(Gtk::CAN_FOCUS);
    buttonSystem->set_relief(Gtk::RELIEF_NONE);
    
    buttonFind->unset_flags(Gtk::CAN_FOCUS);
    buttonFind->set_relief(Gtk::RELIEF_NONE);   
    
    buttonUser->set_relief(Gtk::RELIEF_NONE);
    buttonUser->unset_flags(Gtk::CAN_FOCUS);
    
    scrolledwindowFriend->set_policy(Gtk::POLICY_AUTOMATIC, Gtk::POLICY_AUTOMATIC);
    scrolledwindowFriend->add(*buddyList);


    vboxMain->pack_start(*scrolledwindowFriend);
    vboxMain->pack_start(*hboxMain, Gtk::PACK_SHRINK, 0);


    mainWindow->set_title("好友列表");
    mainWindow->set_default_size(150,400);
    mainWindow->add(*vboxMain);

    buttonSystem->add_accelerator("clicked", 
	    gmm_data->getAccelGroup(), GDK_s, Gdk::CONTROL_MASK, Gtk::ACCEL_VISIBLE);
    
    buttonSystem->add_accelerator("clicked", 
	    gmm_data->getAccelGroup(), GDK_S, Gdk::CONTROL_MASK, Gtk::ACCEL_VISIBLE);
    
    buttonFind->add_accelerator("clicked", 
	    gmm_data->getAccelGroup(), GDK_F, Gdk::CONTROL_MASK, Gtk::ACCEL_VISIBLE);
    
    buttonFind->add_accelerator("clicked", 
	    gmm_data->getAccelGroup(), GDK_f, Gdk::CONTROL_MASK, Gtk::ACCEL_VISIBLE);
    
    buttonUser->add_accelerator("clicked", 
	    gmm_data->getAccelGroup(), GDK_U, Gdk::CONTROL_MASK, Gtk::ACCEL_VISIBLE);

    buttonUser->add_accelerator("clicked", 
	    gmm_data->getAccelGroup(), GDK_u, Gdk::CONTROL_MASK, Gtk::ACCEL_VISIBLE);

    buttonSystem->signal_clicked().connect(sigc::mem_fun(*this,
		&MainWindow::on_btnSystem_clicked), false);

    buttonUser->signal_clicked().connect(sigc::mem_fun(*this,
		&MainWindow::on_btnUser_clicked), false);

    buttonFind->signal_clicked().connect(sigc::mem_fun(*this,
		&MainWindow::on_findBuddy_activate), false);
    
    this->signal_delete_event().connect(sigc::mem_fun(*this,
		&MainWindow::on_delete_event), false);
}

MainWindow::~MainWindow()
{
    for_each(sessionList.begin(),
	    sessionList.end(), mem_fun(&QQSession::destroy));
}

void MainWindow::login(const QQUser& user)
{
    Sessions::iterator iter = find_if(sessionList.begin(), sessionList.end(),
	    bind2nd(mem_fun(&QQSession::compare), user.getUid()));

    if (iter != sessionList.end()) {
	if (QQSession::ONLINE_STATUS == (*iter)->netStatus()) 
	    return;
	else {
	    (*iter)->destroy();
	    sessionList.erase(iter);
	} 
    }
    QQSession* session = new QQSession(user);
    sessionList.push_back(session);
    try {
	session->login();
    }
    catch (const exception& e) {
	fprintf(stderr, "MainWindow::login() error: %s\n", e.what());
	new DisconnectDialog(*this, session->getUid(),
	     	e.what(), false, true);	
    }
}

void MainWindow::refreshSelfStatus(const QQSession& session)
{
    buddyList->refreshSelfStatus(session);
    // 检查一下菜单上的按钮状态
    on_buddyList_row_changed();
}


// 登录超时
bool MainWindow::on_timeout()
{
    Sessions::iterator first = sessionList.begin();
    Sessions::iterator last  = sessionList.end();

    for (; first != last; ) {
	switch ((*first)->netStatus()) {
	    case QQSession::LOGIN_STATUS:
		if (QQSession::STATUS_ERROR == (*first)->tryLogin()) {
		    //登录失败。
		    fprintf(stderr,
			    "MainWindow::on_timeout error QQ: %d login fail\n",
			    (*first)->getUid());
		    new DisconnectDialog(*this, (*first)->getUid(),
			    "登录出错,是否重新连接");
		} 
		break;
	    case QQSession::ONLINE_STATUS:	    // 已经登录
		if (QQSession::STATUS_DISCONNECT == (*first)->keepAlive()) {
		    fprintf(stderr, 
			    "MainWindow::on_timeout error QQ: %d disconnect\n",
			    (*first)->getUid());
		    // 网络断开
		    new DisconnectDialog(*this,
			    (*first)->getUid(),
			    "网络已经断开,是否重新连接");
		}
		break;
	    case QQSession::OFFINE_STATUS:	    // 断线了
		break;
	}
	++first;
    }
    return true;
}

void MainWindow::loginError(QQSession* session, const string& message)
{
    new PasswdErrorDialog(*this, session->getUid(), g2u.convert(message));
}


// 对话框回调函数
void MainWindow::on_passwdErrorDialog_ok(PasswdErrorDialog* dlg)
{
    Sessions::iterator iter = find_if(sessionList.begin(), sessionList.end(),
	    bind2nd(mem_fun(&QQSession::compare), dlg->getId()));
    
    delete dlg; 

    if (iter != sessionList.end()) {
	if (QQSession::OFFINE_STATUS == (*iter)->netStatus()) { 
	    (*iter)->destroy();
	    sessionList.erase(iter);
	    on_userNew_activate(); // 重新打开一个登录对话框.
	} 
    }
}


void MainWindow::on_disconnectDialog_yes(DisconnectDialog* dlg)
{
    Sessions::iterator iter = find_if(sessionList.begin(), sessionList.end(),
	    bind2nd(mem_fun(&QQSession::compare), dlg->getId()));

    delete dlg;

    if (iter != sessionList.end()) {
	if (QQSession::OFFINE_STATUS == (*iter)->netStatus()) {
	    try {
		(*iter)->login();
	    }
	    catch (const exception& e) {
		Gtk::MessageDialog dlg(*this, e.what(), false, Gtk::MESSAGE_ERROR);
		dlg.run();
		int uid = (*iter)->getUid();
		buddyList->removeUser(uid);
		(*iter)->destroy();
		sessionList.erase(iter);
	    }
	}
    }

    if (sessionList.empty()) {
	new LoginWindow(*this);
    }
}

void MainWindow::on_disconnectDialog_no(DisconnectDialog* dlg)
{
    Sessions::iterator iter = find_if(sessionList.begin(), sessionList.end(),
	    bind2nd(mem_fun(&QQSession::compare), dlg->getId()));

    if (iter != sessionList.end()) {
	int uid = (*iter)->getUid();
	(*iter)->destroy();
	sessionList.erase(iter);
	buddyList->removeUser(uid);
    }

    if (sessionList.empty()) {
	new LoginWindow(*this);
    }
    delete dlg;
}


void MainWindow::on_loginWindow_ok(LoginWindow* dlg)
{
    login(dlg->getUser());

    delete dlg;
    this->show_all();
}

void MainWindow::on_loginWindow_cancel(LoginWindow* dlg)
{
    delete dlg;
    if (sessionList.empty())
	Gtk::Main::quit();
}




// 窗口关闭(退出主循环)
bool MainWindow::on_delete_event(GdkEventAny* ev)
{
    Gtk::Main::quit();
    return true;
}

// 初始化函数(主循环开始后调用一次)
void MainWindow::on_initalize()
{
    // 设置4秒的超时, 更新状态,如果登录发生错误,就可以重新登录一次.
    Glib::signal_timeout().connect(sigc::mem_fun(*this, &MainWindow::on_timeout), 4000);
    on_userNew_activate();
}
//
//
QQSession* MainWindow::getSelectSession()
{
    Glib::RefPtr<Gtk::TreeSelection> selection = buddyList->get_selection();	

    Gtk::TreeModel::iterator iter = selection->get_selected();
    QQSession* session = NULL;

    if (selection->count_selected_rows()) 
	session =  buddyList->getSession(iter); 
    else if (!sessionList.empty()) 
	session = *(sessionList.begin());
    
    return session;
}

// 菜单回调函数
//
void MainWindow::on_buddyChat_activate()
{
    Glib::RefPtr<Gtk::TreeSelection> selection = buddyList->get_selection();	
    if (selection) {
	    printf("on_buddyChat_activate::Error\n");
	    return ;
    }

    if (!selection->count_selected_rows())
	return;	    

    Gtk::TreeModel::iterator iter = selection->get_selected();

    QQSession* session = buddyList->getSession(iter);
    if (NULL == session)
	return;

    int type = buddyList->getType(iter);
    if (TREE_ITEM_GROUP == type)
	return;

    BuddyInfo* buddy = NULL;

    uint32_t uid = buddyList->getUid(iter);
    if (TREE_ITEM_CLUSTER == type)
	buddy = session->getClusterInfo(uid);
    else if (TREE_ITEM_BUDDY == type)
	buddy = session->getFriendInfo(uid);

    if (NULL != buddy) {
	session->showMessagePage(buddy);
    }
}

void MainWindow::on_buddyLog_activate()
{
	on_buddyChat_activate();
	
}

void MainWindow::on_buddyInfo_activate()
{
    Glib::RefPtr<Gtk::TreeSelection> selection = buddyList->get_selection();	

    Gtk::TreeModel::iterator iter = selection->get_selected();
    if (!selection->count_selected_rows())
	return;

    QQSession* session = buddyList->getSession(iter);
    if (NULL != session) {
	int uid = buddyList->getUid(iter);
	int type = buddyList->getType(iter);
	if (TREE_ITEM_BUDDY == type)
	{
	    session->sendPacket(OutPacketPtr(
			new GetUserInfoPacket(*session, uid)));
	}
    } 
}

void MainWindow::on_buddyRemove_activate()
{
}


void MainWindow::on_groupNew_activate()
{
}

void MainWindow::on_groupRemove_activate()
{
}



void MainWindow::on_userOnline_activate()
{
    QQSession* session = getSelectSession();
    if (NULL != session) {
	session->changeStatus(QQ_FRIEND_STATUS_ONLINE);
    }
}

void MainWindow::on_userAway_activate()
{
    QQSession* session = getSelectSession();
    if (NULL != session) {
	session->changeStatus(QQ_FRIEND_STATUS_AWAY);
    }
}


void MainWindow::on_userHidden_activate()
{
    QQSession* session = getSelectSession();
    if (NULL != session) {
	session->changeStatus(QQ_FRIEND_STATUS_HIDDEN);
    }
}


void MainWindow::on_userInfo_activate()
{
    QQSession* session = getSelectSession();
    if (NULL != session) {
	session->sendPacket(OutPacketPtr(
		    new GetUserInfoPacket(*session, session->getUid())));
    }
}

void MainWindow::on_userExit_activate()
{
    QQSession* session = getSelectSession();
    if (NULL == session) {
	return;
    }

    Sessions::iterator iter = find(sessionList.begin(), sessionList.end(), session);
    if (iter != sessionList.end()) {
	sessionList.erase(iter);
    }
    uint32_t uid = session->getUid();

    session->logout();
    session->destroy();

    buddyList->removeUser(uid);
    if (sessionList.empty()) {
	new LoginWindow(*this);
	this->hide();
    }
    
}

void MainWindow::on_userNew_activate()
{
    LoginWindow* logdlg = new LoginWindow(*this);
}


void MainWindow::on_about_activate()
{
	Glib::ustring title="关于Cyclone";
	//Gtk::Dialog aboutdlg(title,*this);
	dialogAbout aboutdlg(title,*this);
	aboutdlg.add_button(Gtk::StockID("gtk-ok"), Gtk::RESPONSE_OK);
	aboutdlg.run();
}

void MainWindow::on_SearchUser(QQSession &session)
{
	findBuddyWindow->on_RecvResult(session);
}
void MainWindow::on_findBuddy_activate()
{
    QQSession* session = getSelectSession();
    if ((NULL != session)) {
	if (NULL == findBuddyWindow) {
	    findBuddyWindow = new FindBuddyWindow(session);
	} else {
	    findBuddyWindow->setSession(session);
	    findBuddyWindow->raise();
	}
    }
}

void MainWindow::on_findBuddyWindow_close(FindBuddyWindow* dlg)
{
    g_assert(dlg == findBuddyWindow);
    delete dlg;
    findBuddyWindow = NULL;
}

void MainWindow::on_setPrefer_activate()
{
	QQSession * session =getSelectSession();
	if((NULL!=session)){
		if(NULL==preferWindow){
			preferWindow = new PreferWindow();
		//	preferWindow = new PreferWindow(session);
		}
		else{
		//	preferWindow->setSession(session);
			preferWindow->raise();
		}
	}

}

void MainWindow::on_preferWindow_close(PreferWindow* dlg)
{
    g_assert(dlg == preferWindow);
    delete dlg;
    preferWindow = NULL;
}
/////////////////////////////////

void MainWindow::on_btnSystem_clicked()
{
    systemMenu.popup(
	    sigc::bind<int>(
		sigc::mem_fun(this, &MainWindow::on_popup_menu_pos), SYSTEM_MENU),
	    1, GDK_CURRENT_TIME);
}

void MainWindow::on_btnUser_clicked()
{
    userMenu.popup(
	    sigc::bind<int>(
		sigc::mem_fun(this, &MainWindow::on_popup_menu_pos), USER_MENU),
	    1, GDK_CURRENT_TIME);
}

void MainWindow::on_popup_menu_pos(int& x, int& y, bool& push_in, int id)
{
    GtkWidget *active;
    GtkWidget *child;
    GtkRequisition requisition;
    GList *children;

    int menu_xpos;
    int menu_ypos;
    int menu_height;

    GtkWidget* widget;
    GtkMenu* menu;
    if (SYSTEM_MENU == id ) {
	widget = GTK_WIDGET(buttonSystem->gobj());
	menu = systemMenu.gobj();
    } else {
	widget = GTK_WIDGET(buttonUser->gobj());
	menu= userMenu.gobj();
    }


    gtk_widget_get_child_requisition (GTK_WIDGET(menu), &requisition);
    menu_height = requisition.height;

    gdk_window_get_origin (widget->window, &menu_xpos, &menu_ypos);

    menu_xpos += widget->allocation.x + widget->allocation.width / 2;
    menu_ypos += widget->allocation.y - menu_height + widget->allocation.height / 2;


    if (menu_xpos < 0)
	menu_xpos = 0;

    if (menu_ypos < 0)
	menu_ypos = 0;

    x = menu_xpos;
    y = menu_ypos;
    push_in = true;
}

void MainWindow::on_buddyList_row_changed()
{
    QQSession* session = getSelectSession();
    if (NULL != session) {
	int status = session->getCurrentStatus();
	switch (status) {
	    case QQ_FRIEND_STATUS_ONLINE:
		imageUser->set(pixUser[0]);
		break;
	    case QQ_FRIEND_STATUS_AWAY:
		imageUser->set(pixUser[1]);
		break;
	    case QQ_FRIEND_STATUS_HIDDEN:
		imageUser->set(pixUser[2]);
		break;
	}
    }
		
}
void MainWindow::toggle_visibility()
{
//     printf("and I got to here in Mainwnd\n");
     if (this->is_visible())
          {
//	  	printf("I am going to hide!\n");
	  	  // Save the window position 
		  this->get_position(win_x, win_y);
		  // Hide it 
		  this->hide();
	 }
    else 
    { 
//    	printf("I am going to show!\n");
    // restore the position we saved 
    	this->move(win_x, win_y); 
	this->show();
    } 
}
